#!/usr/bin/python
# -*- coding: UTF-8 -*-
import json
import random
import threading
from collections import OrderedDict

import PlayerManage

KEY_MESSAGE_TYPE = "messageType"
KEY_CARDS_GROUP = "cardsGroup"
KEY_PLAYER_CARDS = "playerCards"
KEY_PLAYER_INFOS = "playerInfos"
KEY_PLAYER_INDEX = "playerIndex"
KEY_PLAYER_NAME = "playerName"
KEY_PLAYER_ICON = "playerIcon"
KEY_PLAYER_SCORE = "playerScore"
KEY_ACTION_TYPE = "actionType"
KEY_SEND_CARD = "cardSend"
KEY_TAKE_GROUP = "groupTake"
KEY_IS_AI = "isAI"
KEY_IS_TEMP = "isTemp"
KEY_ROUND_INDEX = "roundIndex"
KEY_READY_CARDS = "readyCards"
KEY_TAKEING_GROUP = "takingGroup"
KEY_PLAYER_COUNT = "playerCount"

CARDS_COUNT_SUM = 104
CARD_GROUP_COUNT = 4
GROUP_CARD_MAX = 5

class MessageType:
    MESSAGE_GAME_START = "game_start"
    MESSAGE_GAME_PLAY = "game_play"
    MESSAGE_GAME_END = "game_end"
    MESSAGE_NEW_ROUND = "new_round"
    MESSAGE_GAME_SURRENDER = "game_surrender"
    MESSAGE_GOTO_HALL = "goto_hall"
    MESSAGE_ERROR = "error"
    MESSAGE_GAME_CONTINUE = "game_continue"

class ActionType:
    ACTION_TYPE_SEND_A_CARD = "sendACard"
    ACTION_TYPE_TAKE_A_GROUP = "takeAGroup"

class ErrorType:
    ERROR_WRONG_ACTION = "error_wrong_action"

# test: this class should be placed in PlayerManage.py
class PlayerInfo:
    PlayerName = ""
    PlayerStartScore = 100

class PlayerInfoInGame:
    PlayerName = ""
    PlayerScore = 0
    PlayerIndex = -1
    PlayerIcon = 0

class GameManage:

    def __init__(self, roomManager, roomID):
        self.m_roomManager = roomManager
        self.m_nRoomID = roomID
        self.m_rgAllCards = []
        self.m_rgPublicCardsGroup = []
        self.m_rgPlayersCards = []
        self.m_rgCardsPlayerGet = []
        self.m_rgPlayerInfos = []
        self.m_nPlayerCount = 0
        self.m_nCardCountOneRound = 0
        self.m_rgReadyPlayerCard = []
        self.m_nTakingGroupCard = 0
        self.m_dicWaitingInfo = {}
        self.m_nRoundIndex = 0
        self.m_bGameOver = False
        self.m_nTakingGroupPlayer = -1
        self.m_kickTimer = False
    
    def startGame(self, rgPlayerInfos):
        self.__shuffle()
        
        try:
            self.m_nPlayerCount = len(rgPlayerInfos)
            if self.m_nPlayerCount == 3:
                self.m_nCardCountOneRound = 16
            elif self.m_nPlayerCount == 4:
                self.m_nCardCountOneRound = 12
            elif self.m_nPlayerCount == 5:
                self.m_nCardCountOneRound = 10
            else:
                print "Error: current player count is ", self.m_nPlayerCount
            
            # public cards
            i = 0
            self.m_rgPublicCardsGroup = []
            while i < CARD_GROUP_COUNT:
                cardGroup = []
                cardGroup.append(self.__getACard())
                self.m_rgPublicCardsGroup.append(cardGroup)
                i += 1

            # players' cards
            i = 0
            self.m_rgPlayersCards = []
            self.m_rgCardsPlayerGet = []
            while i < self.m_nPlayerCount:
                j = 0
                playerCards = []
                cardsPlayerGet = []
                while j < self.m_nCardCountOneRound * 2:
                    playerCards.append(self.__getACard())
                    j += 1
                self.m_rgPlayersCards.append(playerCards)
                self.m_rgCardsPlayerGet.append(cardsPlayerGet)
                i += 1

            # players' Infos
            index = 0
            self.m_rgPlayerInfos = []
            for playerInfo in rgPlayerInfos:
#                print "playerInfo PlayerIcon : ", playerInfo.PlayerIcon
                playerInfoInGame = PlayerInfoInGame()
                playerInfoInGame.PlayerName = playerInfo.PlayerName
                playerInfoInGame.PlayerScore = playerInfo.PlayerStartScore
                playerInfoInGame.PlayerIcon = playerInfo.PlayerIcon
                playerInfoInGame.PlayerIndex = index
                index += 1
                self.m_rgPlayerInfos.append(playerInfoInGame)

            self.m_nRoundIndex = 1;

            return self.__createGameStartMessage()
        except Exception, e:
            print "error:", e

    def checkIsGameMessage(self, strMessage):
        try:
            dicJsonMessage = json.loads(strMessage)
            if dicJsonMessage.has_key(KEY_MESSAGE_TYPE):
                strMessageType = dicJsonMessage[KEY_MESSAGE_TYPE]
                if strMessageType == MessageType.MESSAGE_GAME_PLAY:
                    return True
                else:
                    return False
            else:
                return False
        
        except ValueError:
            print "GameManage strMessage is not json"
            return False
    
        except Exception, e:
            print "error:", e
            return False

    def __shuffle(self):
        i = 0
        while i < CARDS_COUNT_SUM:
            self.m_rgAllCards.append(i + 1)
            i += 1
        random.shuffle(self.m_rgAllCards)
    
    def __getACard(self):
        try:
            card = self.m_rgAllCards.pop()
            return card
        except Exception,e:
            print "error: ", e
            return 0

    def __createGameStartMessage(self):
        message = OrderedDict()
        message[KEY_MESSAGE_TYPE] = MessageType.MESSAGE_GAME_START
        message[KEY_CARDS_GROUP] = self.m_rgPublicCardsGroup

        playerCardsForJson = []
        for playerCards in self.m_rgPlayersCards:
            playerCardsForJson.append(playerCards)

        message[KEY_PLAYER_CARDS] = playerCardsForJson

        playerInfosForJson = []
        for playerInfo in self.m_rgPlayerInfos:
            playerInfoForJson = {}
            playerInfoForJson[KEY_PLAYER_NAME] = playerInfo.PlayerName
            playerInfoForJson[KEY_PLAYER_SCORE] = playerInfo.PlayerScore
            playerInfoForJson[KEY_PLAYER_INDEX] = playerInfo.PlayerIndex
            playerInfoForJson[KEY_PLAYER_ICON] = playerInfo.PlayerIcon
            playerInfosForJson.append(playerInfoForJson)

        message[KEY_PLAYER_INFOS] = playerInfosForJson
    
        strJsonMessage = json.dumps(message)
        return strJsonMessage

    def receiveAMessage(self, strMessage):
    
        try:
            dicJsonMessage = json.loads(strMessage)
            messageType = dicJsonMessage[KEY_MESSAGE_TYPE]
            
            if messageType == MessageType.MESSAGE_GAME_PLAY:
                return self.__getAGamePlayMessage(dicJsonMessage)
                
        except Exception,e:
            print "error:", e
    

    def __getAGamePlayMessage(self, dicJsonMessage):
        messageType = dicJsonMessage[KEY_MESSAGE_TYPE]
        assert messageType == MessageType.MESSAGE_GAME_PLAY, "should be GAME_PLAY_TYPE"

        try:
            actionType = dicJsonMessage[KEY_ACTION_TYPE]
            actionPlayerIndex = dicJsonMessage[KEY_PLAYER_INDEX]
            
            if actionType == ActionType.ACTION_TYPE_SEND_A_CARD:
                sendCard = dicJsonMessage[KEY_SEND_CARD]

                readyPlayerCard = {}
                readyPlayerCard[KEY_PLAYER_INDEX] = actionPlayerIndex
                readyPlayerCard[KEY_SEND_CARD] = sendCard
                self.m_rgReadyPlayerCard.append(readyPlayerCard)
                self.m_rgPlayersCards[actionPlayerIndex].remove(sendCard)
                
                gameMessage = self.__createASendCardMessage(dicJsonMessage)
                if len(self.m_rgReadyPlayerCard) == self.m_nPlayerCount:
                    self.m_nRoundIndex += 1
                    self.__readyCardsToCardGroup()

                return gameMessage
				
            elif actionType == ActionType.ACTION_TYPE_TAKE_A_GROUP:
				
                if actionPlayerIndex != self.m_dicWaitingInfo[KEY_PLAYER_INDEX]:
                    return self.__createAnErrorActionMessage()

                actionTakeGroup = dicJsonMessage[KEY_TAKE_GROUP]
                self.__playerTakeAGroup(actionPlayerIndex, actionTakeGroup, self.m_dicWaitingInfo[KEY_SEND_CARD])
                
                self.m_dicWaitingInfo = {}
				
                if self.m_kickTimer != False:
                    self.m_kickTimer.cancel()
                
                return self.__createATakeGroupMessage(dicJsonMessage)
				
            else:
                return self.__createAnErrorActionMessage()

        except Exception,e:
            print "error:", e

    def __readyCardsToCardGroup(self):
        try:
            rgReadCards = []
            for dicReadyCard in self.m_rgReadyPlayerCard:
                rgReadCards.append(dicReadyCard[KEY_SEND_CARD])
            rgReadCards.sort()
            
            rgGroupsHeads = []
            for group in self.m_rgPublicCardsGroup:
                rgGroupsHeads.append(group[len(group) - 1])
            rgGroupsHeads.sort()
            nSmallestGroupHead = rgGroupsHeads[0]

            while 0 < len(rgReadCards):
                actionCard = rgReadCards[0]
                actionPlayerIndex = -1
                for dicReadyCard in self.m_rgReadyPlayerCard:
                    if dicReadyCard[KEY_SEND_CARD] == actionCard:
                        actionPlayerIndex = dicReadyCard[KEY_PLAYER_INDEX]
                        break

                #case 1  card is smallest of all group head
                if actionCard < nSmallestGroupHead:
                    del rgReadCards[0]
                    m_nTakingGroupCard = actionCard
                    self.m_dicWaitingInfo = dicReadyCard
                    self.m_rgReadyPlayerCard.remove(dicReadyCard)

#                    print "Server Wating take group"
#                    print "Server Current Public Cards : ", self.m_rgPublicCardsGroup

                    self.__startKickPlayerTimer(actionPlayerIndex)
                    break
                #case 2  card isn't smallest, find the right group (the biggest one of all the group'heads smaller than the actionCard)
                else:
                    nGroupIndex = -1
                    nBiggestSmallerGroupHead = 0
                    i = 0
                    while i < CARD_GROUP_COUNT: 
                        group = self.m_rgPublicCardsGroup[i]
                        groupHead = group[len(group) - 1]
                        if groupHead < actionCard and groupHead > nBiggestSmallerGroupHead:
                            nBiggestSmallerGroupHead = groupHead
                            nGroupIndex = i
                        i += 1

                    if nGroupIndex < 0 or nBiggestSmallerGroupHead <= 0 :
                        raise Exception("Server not find the right group")
                    else:
                        if len(self.m_rgPublicCardsGroup[nGroupIndex]) < GROUP_CARD_MAX:
                            self.m_rgPublicCardsGroup[nGroupIndex].append(actionCard)
                        else:
                            for cardNum in self.m_rgPublicCardsGroup[nGroupIndex]:
                                self.m_rgPlayerInfos[actionPlayerIndex].PlayerScore -= self.getCardScore(cardNum)
                                self.m_rgCardsPlayerGet[actionPlayerIndex].append(cardNum)
                        
                            self.m_rgPublicCardsGroup[nGroupIndex] = []
                            self.m_rgPublicCardsGroup[nGroupIndex].append(actionCard)
#                            print "Player%d's Score:%d, get Cards:" % (actionPlayerIndex, self.m_rgPlayerInfos[actionPlayerIndex].PlayerScore) , self.m_rgCardsPlayerGet[actionPlayerIndex]

                        self.m_rgReadyPlayerCard.remove(dicReadyCard)
#                        print "Current Public Cards : ", self.m_rgPublicCardsGroup

                del rgReadCards[0]
    
                i = 0
                while i < self.m_nPlayerCount:
                    if len(self.m_rgPlayersCards[i]) != 0:
                        break
                    else:
                        i += 1

                if i == self.m_nPlayerCount:
                    self.m_bGameOver = True
                        
        except Exception,e:
            print "error : ", e
			
    def __playerTakeAGroup(self, nPlayerIndex, nGroupIndex, nPlayerCard):
        rgCardGroup = self.m_rgPublicCardsGroup[nGroupIndex]
        for card in rgCardGroup:
            self.m_rgCardsPlayerGet[nPlayerIndex].append(card)
            self.m_rgPlayerInfos[nPlayerIndex].PlayerScore -= self.getCardScore(card)
           
        self.m_rgPublicCardsGroup[nGroupIndex] = []
        self.m_rgPublicCardsGroup[nGroupIndex].append(nPlayerCard)

#        print "Player%d's Score:%d, get Cards:" % (nPlayerIndex, self.m_rgPlayerInfos[nPlayerIndex].PlayerScore) , self.m_rgCardsPlayerGet[nPlayerIndex]
        self.__readyCardsToCardGroup()

    def getCardScore(self, cardNum):
        if cardNum == 55:
            return 7
        elif cardNum > 10 and ((cardNum / 10) == (cardNum % 10)):
            return 5
        elif cardNum % 10 == 0:
            return 3
        elif cardNum % 10 == 5:
            return 2
        else:
            return 1

    def __createASendCardMessage(self, dicJsonMessage):
        dicServerGamePlayMessage = OrderedDict()
        dicServerGamePlayMessage[KEY_MESSAGE_TYPE] = MessageType.MESSAGE_GAME_PLAY
        dicServerGamePlayMessage[KEY_ACTION_TYPE] = ActionType.ACTION_TYPE_SEND_A_CARD
        dicServerGamePlayMessage[KEY_PLAYER_INDEX] = dicJsonMessage[KEY_PLAYER_INDEX]
        dicServerGamePlayMessage[KEY_SEND_CARD] = dicJsonMessage[KEY_SEND_CARD]
        dicServerGamePlayMessage[KEY_IS_AI] = dicJsonMessage[KEY_IS_AI]
        dicServerGamePlayMessage[KEY_IS_TEMP] = dicJsonMessage[KEY_IS_TEMP]
        dicServerGamePlayMessage[KEY_ROUND_INDEX] = self.m_nRoundIndex
        
        strJsonMessage = json.dumps(dicServerGamePlayMessage)
        return strJsonMessage

    def __createATakeGroupMessage(self, dicJsonMessage):
        dicServerGamePlayMessage = OrderedDict()
        dicServerGamePlayMessage[KEY_MESSAGE_TYPE] = MessageType.MESSAGE_GAME_PLAY
        dicServerGamePlayMessage[KEY_ACTION_TYPE] = ActionType.ACTION_TYPE_TAKE_A_GROUP
        dicServerGamePlayMessage[KEY_PLAYER_INDEX] = dicJsonMessage[KEY_PLAYER_INDEX]
        dicServerGamePlayMessage[KEY_TAKE_GROUP] = dicJsonMessage[KEY_TAKE_GROUP]
        dicServerGamePlayMessage[KEY_IS_AI] = dicJsonMessage[KEY_IS_AI]
        dicServerGamePlayMessage[KEY_IS_TEMP] = dicJsonMessage[KEY_IS_TEMP]
        
        strJsonMessage = json.dumps(dicServerGamePlayMessage)
        return strJsonMessage
		
    def __createAnErrorActionMessage(self):
        dicServerGamePlayMessage = OrderedDict()
        dicServerGamePlayMessage[KEY_MESSAGE_TYPE] = MessageType.MESSAGE_ERROR
    
        strJsonMessage = json.dumps(dicServerGamePlayMessage)
        return strJsonMessage

# for midway AI
    def getPlayerLeftCards(self, nPlayerIndex):
        try:
            return self.m_rgPlayersCards[nPlayerIndex]
        except Exception,e:
            print "error : ", e

# for returned Player
    def getGameContinueMessage(self):
        try:
            message = OrderedDict()
            message[KEY_MESSAGE_TYPE] = MessageType.MESSAGE_GAME_CONTINUE
            message[KEY_CARDS_GROUP] = self.m_rgPublicCardsGroup
                
            playerCardsForJson = []
            for playerCards in self.m_rgPlayersCards:
                playerCardsForJson.append(playerCards)

            message[KEY_PLAYER_CARDS] = playerCardsForJson
                
            playerInfosForJson = []
            for playerInfo in self.m_rgPlayerInfos:
                playerInfoForJson = {}
                playerInfoForJson[KEY_PLAYER_NAME] = playerInfo.PlayerName
                playerInfoForJson[KEY_PLAYER_SCORE] = playerInfo.PlayerScore
                playerInfoForJson[KEY_PLAYER_INDEX] = playerInfo.PlayerIndex
                playerInfoForJson[KEY_PLAYER_ICON] = playerInfo.PlayerIcon
                playerInfosForJson.append(playerInfoForJson)

            message[KEY_PLAYER_INFOS] = playerInfosForJson
            
            message[KEY_PLAYER_COUNT] = self.m_nPlayerCount
            message[KEY_ROUND_INDEX] = self.m_nRoundIndex
            message[KEY_READY_CARDS] = self.m_rgReadyPlayerCard
            message[KEY_TAKEING_GROUP] = self.m_dicWaitingInfo
            
            strJsonMessage = json.dumps(message)
            print strJsonMessage
            return strJsonMessage
            
        except Exception,e:
            print "error : ", e

#for take group action kick player
    def __startKickPlayerTimer(self, nPlayerIndex):
        self.m_kickTimer = threading.Timer(35, self.__kickPlayer, [nPlayerIndex])
        self.m_kickTimer.start()
        print "start kick timer"

    def __kickPlayer(self, nPlayerIndex):
        print "kick player %d" % nPlayerIndex
        self.m_roomManager.kickPlayerOut(nPlayerIndex, self.m_nRoomID)

#test

#game = GameManage()
#player1 = PlayerInfo()
#player1.PlayerName = "5km1"
#player1.PlayerScore = 0
#
#player2 = PlayerInfo()
#player2.PlayerName = "5km2"
#player2.PlayerScore = 0
#
#player3 = PlayerInfo()
#player3.PlayerName = "5km3"
#player3.PlayerScore = 0
#
#playerInfos = [player1, player2, player3]
#gameStartJsonStr = game.startGame(playerInfos)
#
#dicJsonMessage = json.loads(gameStartJsonStr)
#publicCards = dicJsonMessage[KEY_CARDS_GROUP]
#print "Public Cards : ", publicCards
#
#playerCards = dicJsonMessage[KEY_PLAYER_CARDS]
#nPlayerCount = len(playerCards)
#
#while 1:
#    command = input("Command:")
#    if command ==  'take group':
#        nPlayerIndex = input("PlayerIndex:")
#        nTakeGroup = input("TakeGroup:")
#
#        gamePlayMessage = '{\"messageType\":\"game_play\", \"actionType\":\"takeAGroup\", \"groupTake\":%d, \"playerIndex\":%d}'  % (nTakeGroup, nPlayerIndex)
#        game.receiveAMessage(gamePlayMessage)
#    elif command == "next round":
#        i = 0
#        while i < nPlayerCount:
#            sendCard = playerCards[i][0]
#            del playerCards[i][0]
#            print "Player:%d SendCard:%d" % (i, sendCard)
#            gamePlayMessage = '{\"messageType\":\"game_play\", \"actionType\":\"sendACard\", \"playerIndex\":%d, \"cardSend\":%d}' % (i,sendCard)
#            game.receiveAMessage(gamePlayMessage)
#            i += 1
#    else:
#        continue
